# server.py - 五子棋网络对战和聊天服务端

import socket
import threading
import json
import time
import random
import logging
from datetime import datetime
import pygame
from db_manager import DatabaseManager
# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler("server_log.txt"),
        logging.StreamHandler()
    ]
)

class GobangServer:
    def __init__(self, host='0.0.0.0', port=5000):
        self.host = host
        self.port = port
        self.server_socket = None
        self.clients = {}  # {client_id: {"socket": socket, "username": username, "game_id": game_id}}
        self.waiting_players = []  # 等待匹配的玩家
        self.games = {}  # {game_id: {"black": client_id, "white": client_id, "board": board, "current_player": "black"}}
        self.client_id_counter = 0
        self.game_id_counter = 0
        self.lock = threading.Lock()
        self.client_last_active = {}  # 记录客户端最后活动时间
        self.client_disconnect_lock = threading.Lock()  # 防止重复处理断开连接
        self.db_manager = DatabaseManager()
        self.db_manager.connect()

    
    def start(self):
        """启动服务器"""
        try:
            self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            self.server_socket.bind((self.host, self.port))
            self.server_socket.listen(5)
            logging.info(f"服务器启动成功，监听地址: {self.host}:{self.port}")
            
            # 启动匹配线程
            matching_thread = threading.Thread(target=self.match_players)
            matching_thread.daemon = True
            matching_thread.start()
            
            # 启动心跳检测线程
            heartbeat_thread = threading.Thread(target=self.check_client_heartbeats)
            heartbeat_thread.daemon = True
            heartbeat_thread.start()
            
            # 主循环接受客户端连接
            while True:
                client_socket, address = self.server_socket.accept()
                logging.info(f"新客户端连接: {address}")
                print(f"线程启动")
                
                # 为每个客户端创建一个处理线程
                client_thread = threading.Thread(target=self.handle_client, args=(client_socket, address))
                client_thread.daemon = True
                client_thread.start()
                
        except Exception as e:
            logging.error(f"服务器启动错误: {e}")
        finally:
            if self.server_socket:
                self.server_socket.close()
                logging.info("服务器已关闭")
    
    def handle_client(self, client_socket, address):
        """处理客户端连接"""
        client_id = None
        buffer = ""
        try:
            # 循环接收客户端消息
            while True:
                data = client_socket.recv(4096)
                if not data:
                    break
                
                # 将接收到的数据添加到缓冲区
                buffer += data.decode('utf-8')
                
                # 处理缓冲区中的所有完整JSON消息
                while True:
                    try:
                        # 尝试解析一个JSON对象
                        message, index = json.JSONDecoder().raw_decode(buffer)
                        # 从缓冲区中移除已处理的消息
                        buffer = buffer[index:].strip()
                        
                        # 处理消息
                        if message.get("type") == "login":
                            username = message.get("username", f"玩家{self.client_id_counter}")
                            
                            # 分配客户端ID
                            with self.lock:
                                client_id = self.client_id_counter
                                self.client_id_counter += 1
                                self.clients[client_id] = {
                                    "socket": client_socket,
                                    "username": username,
                                    "game_id": None
                                }
                            
                            # 发送登录成功响应
                            self.send_message(client_id, {
                                "type": "login_response",
                                "status": "success",
                                "client_id": client_id,
                                "message": f"欢迎 {username}!"
                            })
                            
                            logging.info(f"客户端 {client_id} ({username}) 登录成功")
                        elif client_id is not None:
                            # 处理其他类型的消息
                            self.process_message(client_id, message)
                        
                        if not buffer:
                            break
                    except json.JSONDecodeError:
                        # 如果不是完整的JSON，等待更多数据
                        break
        
        except Exception as e:
            logging.error(f"处理客户端 {client_id} 时出错: {e}")

        
        finally:
            # 客户端断开连接
            if client_id is not None:
                self.handle_client_disconnect(client_id)
    
    def handle_client_disconnect(self, client_id):
        """处理客户端断开连接"""
        # 使用专门的锁防止重复处理同一客户端的断开连接
        with self.client_disconnect_lock:
            # 检查客户端是否已经被处理过
            if client_id not in self.clients:
                return
                
            # 获取客户端信息
            with self.lock:
                if client_id in self.clients:
                    username = self.clients[client_id]["username"]
                    game_id = self.clients[client_id]["game_id"]
                    
                    # 如果玩家在游戏中，通知对手
                    if game_id is not None and game_id in self.games:
                        game = self.games[game_id]
                        opponent_id = game["black"] if game["white"] == client_id else game["white"]
                        
                        if opponent_id in self.clients:
                            # 通知对手，对方断开连接
                            self.send_message(opponent_id, {
                                "type": "opponent_disconnected",
                                "message": f"对手 {username} 已断开连接",
                                "winner": "black" if game["black"] == opponent_id else "white"
                            })
                             
                            # 添加日志
                            logging.info(f"游戏 {game_id}: 玩家 {client_id} ({username}) 断开连接，对手 {opponent_id} ({self.clients[opponent_id]['username']}) 获胜")
                        
                        # 结束游戏
                        del self.games[game_id]
                    
                    # 如果玩家在等待队列中，移除
                    if client_id in self.waiting_players:
                        self.waiting_players.remove(client_id)
                    
                    # 从最后活动记录中移除
                    if client_id in self.client_last_active:
                        del self.client_last_active[client_id]
                    
                    # 关闭socket并移除客户端
                    try:
                        self.clients[client_id]["socket"].close()
                    except:
                        pass
                    
                    del self.clients[client_id]
                    logging.info(f"客户端 {client_id} ({username}) 已断开连接")
    
    def process_message(self, client_id, message):
        """处理客户端消息"""
        # 更新客户端最后活动时间
        self.client_last_active[client_id] = time.time()
        
        message_type = message.get("type")
        
        # 客户端主动断开连接
        if message_type == "client_disconnect":
            logging.info(f"客户端 {client_id} ({self.clients[client_id]['username']}) 主动请求断开连接")
            self.handle_client_disconnect(client_id)
            return
        
        # 处理心跳消息
        if message_type == "heartbeat":
            # 回复心跳
            self.send_message(client_id, {"type": "heartbeat_response"})
            return
        
        if message_type == "rematch_request":
            print(f"收到重新比赛请求")
            # 玩家请求重新比赛
            game_id = self.clients[client_id]["game_id"]
            if game_id is not None and game_id in self.games:
                print(f"游戏 {game_id} 存在")
                game = self.games[game_id]
                opponent_id = game["white"] if game["black"] == client_id else game["black"]
                
                # 发送重新比赛请求给对手
                rematch_request = {
                    "type": "rematch_request",
                    "username": self.clients[client_id]["username"]
                }
                
                self.send_message(opponent_id, rematch_request)
                logging.info(f"游戏 {game_id}: 玩家 {client_id} ({self.clients[client_id]['username']}) 请求重新比赛")
            return
        
        elif message_type == "rematch_response":
            # 玩家回应重新比赛请求
            allowed = message.get("allowed", False)
            game_id = self.clients[client_id]["game_id"]
            
            if game_id is not None and game_id in self.games:
                game = self.games[game_id]
                opponent_id = game["white"] if game["black"] == client_id else game["black"]
                
                # 构造回应消息
                response = {
                    "type": "rematch_response",
                    "allowed": allowed,
                    "username": self.clients[client_id]["username"]
                }
                
                # 发送给请求者
                self.send_message(opponent_id, response)
                
                if allowed:
                    # 如果同意重新比赛，重置游戏状态
                    logging.info(f"游戏 {game_id}: 玩家 {client_id} ({self.clients[client_id]['username']}) 同意重新比赛")
                    
                    # 重置游戏状态
                    game["board"] = [[0 for _ in range(15)] for _ in range(15)]
                    game["move_history"] = []
                    game["current_player"] = "black"
                    game["status"] = "playing"
                    game["undo_requested"] = False
                    game["undo_requester"] = None
                    
                    # 重置计时器
                    game["timer"] = {
                        "black": 30,
                        "white": 30
                    }
                    
                    # 通知双方玩家游戏重新开始
                    black_id = game["black"]
                    white_id = game["white"]
                    
                    # 发送给黑方
                    self.send_message(black_id, {
                        "type": "match_found",
                        "role": "black",
                        "opponent": self.clients[white_id]["username"],
                        "black_time": game["timer"]["black"],
                        "white_time": game["timer"]["white"],
                        "game_over": False
                    })
                    
                    # 发送给白方
                    self.send_message(white_id, {
                        "type": "match_found",
                        "role": "white",
                        "opponent": self.clients[black_id]["username"],
                        "black_time": game["timer"]["black"],
                        "white_time": game["timer"]["white"],
                        "game_over": False
                    })
                else:
                    logging.info(f"游戏 {game_id}: 玩家 {client_id} ({self.clients[client_id]['username']}) 拒绝重新比赛")
            return
        
        if message_type == "find_game":
            # 玩家请求匹配游戏
            with self.lock:
                if client_id not in self.waiting_players and self.clients[client_id]["game_id"] is None:
                    self.waiting_players.append(client_id)
                    logging.info(f"客户端 {client_id} ({self.clients[client_id]['username']}) 加入匹配队列")
                    
                    self.send_message(client_id, {
                        "type": "waiting_match",
                        "message": "正在寻找对手..."
                    })
        
        elif message_type == "move":
            # 玩家落子
            game_id = self.clients[client_id]["game_id"]
            if game_id is not None and game_id in self.games:
                game = self.games[game_id]
                
                # 检查是否有悔棋请求待处理
                if game.get("undo_requested", False):
                    # 有悔棋请求待处理，拒绝落子
                    self.send_message(client_id, {
                        "type": "error",
                        "message": "有悔棋请求待处理，请先回应"
                    })
                    return
                
                # 检查是否轮到该玩家
                is_black = (game["black"] == client_id)
                if (is_black and game["current_player"] == "black") or (not is_black and game["current_player"] == "white"):
                    x = message.get("x")
                    y = message.get("y")
                    
                    # 验证落子位置
                    if 0 <= x < 15 and 0 <= y < 15 and game["board"][y][x] == 0:
                        # 更新棋盘
                        piece = 1 if is_black else 2  # 1表示黑棋，2表示白棋
                        game["board"][y][x] = piece
                        
                        # 记录落子历史
                        if "move_history" not in game:
                            game["move_history"] = []
                        game["move_history"].append((x, y, piece, client_id))
                        
                        # 检查是否获胜 - 只有在有足够落子后才检查
                        is_win = False
                        if len(game["move_history"]) >= 9:  # 至少需要5个同色棋子才可能获胜
                            is_win = self.check_win(game["board"], x, y)
                        
                        # 切换当前玩家
                        game["current_player"] = "white" if game["current_player"] == "black" else "black"
                        
                        # 重置计时器
                        if "timer" not in game:
                            game["timer"] = {}
                        game["timer"]["black"] = 30  # 30秒
                        game["timer"]["white"] = 30  # 30秒
                        
                        # 通知双方玩家
                        move_data = {
                            "type": "move_response",
                            "x": x,
                            "y": y,
                            "piece": "black" if is_black else "white",
                            "next_player": game["current_player"],
                            "black_time": game["timer"]["black"],
                            "white_time": game["timer"]["white"]
                        }
                        
                        if is_win:
                            move_data["game_over"] = True
                            move_data["winner"] = "black" if is_black else "white"
                            game["status"] = "finished"
                        
                        self.send_message(game["black"], move_data)
                        self.send_message(game["white"], move_data)
                        
                        logging.info(f"游戏 {game_id}: 玩家 {client_id} 在 ({x},{y}) 落子")
                        
                        if is_win:
                            logging.info(f"游戏 {game_id}: {'黑棋' if is_black else '白棋'} 获胜")
                            # 发送对手信息用于更新排行榜
                            winner_id = client_id  # 当前落子的玩家获胜
                            win_username = self.clients[winner_id]["username"]
                            loser_id = game["white"] if is_black else game["black"]
                            loss_username = self.clients[loser_id]["username"]
                            self.server_update_ranking(win_username, 'win')
                            self.server_update_ranking(loss_username,'loss')
                            


        
        elif message_type == "chat":
            # 聊天消息
            game_id = self.clients[client_id]["game_id"]
            if game_id is not None and game_id in self.games:
                game = self.games[game_id]
                content = message.get("content", "")
                username = self.clients[client_id]["username"]
                
                # 检查是否是对悔棋请求的回复
                if game.get("undo_requested") and game["undo_requester"] != client_id:
                    content_lower = content.strip().lower()
                    if content_lower in ["同意", "yes", "ok", "agree"]:
                        # 同意悔棋
                        logging.info(f"通过聊天同意悔棋: 游戏 {game_id}, 玩家 {client_id}")
                        self.handle_undo_response(game_id, client_id, True)
                        return
                    elif content_lower in ["拒绝", "no", "disagree", "reject"]:
                        # 拒绝悔棋
                        logging.info(f"通过聊天拒绝悔棋: 游戏 {game_id}, 玩家 {client_id}")
                        self.handle_undo_response(game_id, client_id, False)
                        return
                
                # 构造聊天消息
                chat_message = {
                    "type": "chat_message",
                    "username": username,
                    "content": content,
                    "timestamp": datetime.now().strftime("%H:%M:%S")
                }
                
                # 发送给双方
                self.send_message(game["black"], chat_message)
                self.send_message(game["white"], chat_message)
                
                logging.info(f"游戏 {game_id}: 玩家 {username} 发送消息: {content}")
        
        elif message_type == "surrender":
            # 玩家投降
            game_id = self.clients[client_id]["game_id"]
            if game_id is not None and game_id in self.games:
                game = self.games[game_id]
                opponent_id = game["white"] if game["black"] == client_id else game["black"]
                
                # 确定获胜者
                winner_id = opponent_id
                winner_role = "black" if game["black"] == winner_id else "white"
                
                # 发送游戏结束消息给双方
                game_over_message = {
                    "type": "game_over",
                    "reason": "surrender",
                    "winner": winner_role,
                    "message": f"{self.clients[client_id]['username']} 已投降"
                }
                
                self.send_message(client_id, game_over_message)
                self.send_message(opponent_id, game_over_message)
                
                # 发送对手信息用于更新排行榜
                logging.info(f"游戏 {game_id}: 玩家 {client_id} ({self.clients[client_id]['username']}) 投降，玩家 {opponent_id} ({self.clients[opponent_id]['username']}) 获胜")
                
        
        elif message_type == "timeout":
            # 玩家超时
            game_id = self.clients[client_id]["game_id"]
            if game_id is not None and game_id in self.games:
                game = self.games[game_id]
                
                # 确保游戏已经开始且有至少一步落子
                if "move_history" not in game or len(game["move_history"]) < 1:
                    # 游戏刚开始，忽略超时
                    return
                
                is_black = (game["black"] == client_id)
                opponent_id = game["white"] if is_black else game["black"]
                
                # 构造超时者的消息
                timeout_message_for_timeout_player = {
                    "type": "game_over",
                    "reason": "timeout",
                    "winner": "white" if is_black else "black",
                    "message": "您已超时，游戏结束"
                }
                
                # 构造对手的消息
                timeout_message_for_opponent = {
                    "type": "game_over",
                    "reason": "timeout",
                    "winner": "white" if is_black else "black",
                    "message": f"对手 {self.clients[client_id]['username']} 已超时，您获胜！"
                }
                
                # 发送给双方
                self.send_message(client_id, timeout_message_for_timeout_player)
                self.send_message(opponent_id, timeout_message_for_opponent)
                
                # 结束游戏
                game["status"] = "finished"
                
                # 发送对手信息用于更新排行榜
                winner_id = opponent_id  # 对手获胜
                self.send_opponent_info(game_id, winner_id)
                
                # 游戏结束，删除游戏并重置客户端状态
                del self.games[game_id]
                
                # 重置客户端游戏状态，确保可以参与新的匹配
                self.reset_client_game_state(client_id)
                self.reset_client_game_state(opponent_id)
                
                logging.info(f"游戏 {game_id}: 玩家 {client_id} ({self.clients[client_id]['username']}) 超时")
        
        elif message_type == "undo_request":
            # 悔棋请求
            game_id = self.clients[client_id]["game_id"]
            if game_id is not None and game_id in self.games:
                game = self.games[game_id]
                opponent_id = game["white"] if game["black"] == client_id else game["black"]
                
                # 检查玩家是否有棋可以悔
                has_own_move = False
                if "move_history" in game:
                    for _, _, _, player_id in game["move_history"]:
                        if player_id == client_id:
                            has_own_move = True
                            break
                
                if not has_own_move:
                    # 发送错误消息
                    self.send_message(client_id, {
                        "type": "error",
                        "message": "您还没有落子，无法悔棋"
                    })
                    return
                
                # 记录谁请求的悔棋
                game["undo_requested"] = True
                game["undo_requester"] = client_id
                
                # 发送悔棋请求给对手
                undo_request = {
                    "type": "undo_request",
                    "username": self.clients[client_id]["username"]
                }
                
                self.send_message(opponent_id, undo_request)
                
                logging.info(f"游戏 {game_id}: 玩家 {client_id} ({self.clients[client_id]['username']}) 请求悔棋")
        
        elif message_type == "undo_response":
            # 悔棋回应
            allowed = message.get("allowed", False)
            game_id = self.clients[client_id]["game_id"]
            
            if game_id is not None and game_id in self.games:
                game = self.games[game_id]
                requester_id = game.get("undo_requester")
                
                if requester_id and requester_id in self.clients:
                    # 构造回应消息
                    response = {
                        "type": "undo_response",
                        "allowed": allowed,
                        "username": self.clients[client_id]["username"]
                    }
                    
                    # 发送给请求者
                    self.send_message(requester_id, response)
                    
                    if allowed:
                        # 如果同意悔棋，需要回退棋盘状态
                        if "move_history" in game and len(game["move_history"]) >= 1:
                            # 只移除悔棋方的最后一步
                            for i in range(len(game["move_history"]) - 1, -1, -1):
                                move = game["move_history"][i]
                                _, _, _, player_id = move
                                if player_id == requester_id:
                                    # 找到悔棋方的最后一步
                                    x, y, _, _ = move
                                    # 清除棋盘上的棋子
                                    game["board"][y][x] = 0
                                    # 从历史中移除
                                    game["move_history"].pop(i)
                                    break
                            
                            # 设置当前玩家为请求悔棋的一方
                            game["current_player"] = "black" if requester_id == game["black"] else "white"
                            
                            # 重置计时器
                            game["timer"]["black"] = 30
                            game["timer"]["white"] = 30
                            
                            # 发送棋盘更新消息给双方
                            undo_update = {
                                "type": "undo_update",
                                "board": game["board"],
                                "current_player": game["current_player"],
                                "black_time": game["timer"]["black"],
                                "white_time": game["timer"]["white"],
                                "requester_id": requester_id,
                                "requester_role": "black" if requester_id == game["black"] else "white"
                            }
                            
                            # 发送给双方
                            self.send_message(game["black"], undo_update)
                            self.send_message(game["white"], undo_update)
                            
                            logging.info(f"游戏 {game_id}: 悔棋成功，玩家 {requester_id} 可以重新落子")
                    
                    # 重置悔棋请求状态
                    game["undo_requested"] = False
                    game["undo_requester"] = None
                    
                    logging.info(f"游戏 {game_id}: 玩家 {client_id} {'同意' if allowed else '拒绝'}了悔棋请求")
    
    def handle_undo_response(self, game_id, responder_id, allowed):
        """处理悔棋请求的回应"""
        if game_id in self.games:
            game = self.games[game_id]
            requester_id = game.get("undo_requester")
            
            if requester_id and requester_id in self.clients:
                # 构造回应消息
                response = {
                    "type": "undo_response",
                    "allowed": allowed,
                    "username": self.clients[responder_id]["username"]
                }
                
                # 发送给请求者
                self.send_message(requester_id, response)
                
                if allowed:
                    # 如果同意悔棋，需要回退棋盘状态
                    if "move_history" in game and len(game["move_history"]) >= 1:
                        # 只移除悔棋方的最后一步
                        for i in range(len(game["move_history"]) - 1, -1, -1):
                            move = game["move_history"][i]
                            _, _, _, player_id = move
                            if player_id == requester_id:
                                # 找到悔棋方的最后一步
                                x, y, _, _ = move
                                # 清除棋盘上的棋子
                                game["board"][y][x] = 0
                                # 从历史中移除
                                game["move_history"].pop(i)
                                break
                        
                        # 设置当前玩家为请求悔棋的一方
                        game["current_player"] = "black" if requester_id == game["black"] else "white"
                        
                        # 重置计时器
                        if "timer" in game:
                            game["timer"]["black"] = 30
                            game["timer"]["white"] = 30
                        
                        # 发送棋盘更新消息给双方
                        undo_update = {
                            "type": "undo_update",
                            "board": game["board"],
                            "current_player": game["current_player"],
                            "black_time": game["timer"]["black"],
                            "white_time": game["timer"]["white"],
                            "requester_id": requester_id,
                            "requester_role": "black" if requester_id == game["black"] else "white"
                        }
                        
                        # 发送给双方
                        self.send_message(game["black"], undo_update)
                        self.send_message(game["white"], undo_update)
                        
                        logging.info(f"游戏 {game_id}: 悔棋成功，玩家 {requester_id} 可以重新落子")
                
                # 重置悔棋请求状态
                game["undo_requested"] = False
                game["undo_requester"] = None
                
                logging.info(f"游戏 {game_id}: 玩家 {responder_id} {'同意' if allowed else '拒绝'}了悔棋请求")
    
    def match_players(self):
        """匹配玩家线程"""
        while True:
            with self.lock:
                # 如果有至少两名等待的玩家，进行匹配
                if len(self.waiting_players) >= 2:
                    player1_id = self.waiting_players.pop(0)
                    player2_id = self.waiting_players.pop(0)
                    
                    # 确保玩家仍然连接
                    if player1_id in self.clients and player2_id in self.clients:
                        # 创建新游戏
                        game_id = self.game_id_counter
                        self.game_id_counter += 1
                        
                        # 随机分配黑白棋
                        if random.choice([True, False]):
                            black_id, white_id = player1_id, player2_id
                        else:
                            black_id, white_id = player2_id, player1_id
                        
                        # 初始化棋盘 (0: 空, 1: 黑, 2: 白)
                        board = [[0 for _ in range(15)] for _ in range(15)]
                        
                        # 初始化计时器
                        timer = {
                            "black": 30,  # 30秒
                            "white": 30   # 30秒
                        }
                        
                        self.games[game_id] = {
                            "black": black_id,
                            "white": white_id,
                            "board": board,
                            "current_player": "black",
                            "status": "playing",
                            "move_history": [],  # 初始化空的落子历史
                            "timer": timer       # 初始化计时器
                        }
                        
                        # 更新玩家状态
                        self.clients[black_id]["game_id"] = game_id
                        self.clients[white_id]["game_id"] = game_id
                        
                        # 通知玩家游戏开始
                        self.send_message(black_id, {
                            "type": "game_start",
                            "role": "black",
                            "opponent": self.clients[white_id]["username"],
                            "first_move": True,
                            "game_over": False,  # 明确指定游戏未结束
                            "black_time": timer["black"],
                            "white_time": timer["white"]
                        })
                        
                        self.send_message(white_id, {
                            "type": "game_start",
                            "role": "white",
                            "opponent": self.clients[black_id]["username"],
                            "first_move": False,
                            "game_over": False,  # 明确指定游戏未结束
                            "black_time": timer["black"],
                            "white_time": timer["white"]
                        })
                        
                        logging.info(f"游戏 {game_id} 开始: 黑棋 {self.clients[black_id]['username']} vs 白棋 {self.clients[white_id]['username']}")
            
            # 每秒检查一次
            time.sleep(1)
    
    def send_message(self, client_id, message):
        """发送消息给客户端"""
        if client_id in self.clients:
            try:
                # 直接发送JSON字符串，不添加长度前缀
                self.clients[client_id]["socket"].send(json.dumps(message).encode('utf-8'))
            except Exception as e:
                logging.error(f"向客户端 {client_id} 发送消息时出错: {e}")
                self.handle_client_disconnect(client_id)
    
    def check_win(self, board, x, y):
        """检查是否有五子连珠"""
        piece = board[y][x]
        directions = [(1, 0), (0, 1), (1, 1), (1, -1)]  # 横、竖、右下、右上
        
        for dx, dy in directions:
            count = 1  # 当前位置已经有一个棋子
            
            # 正向检查
            for i in range(1, 5):
                nx, ny = x + dx * i, y + dy * i
                if 0 <= nx < 15 and 0 <= ny < 15 and board[ny][nx] == piece:
                    count += 1
                else:
                    break
            
            # 反向检查
            for i in range(1, 5):
                nx, ny = x - dx * i, y - dy * i
                if 0 <= nx < 15 and 0 <= ny < 15 and board[ny][nx] == piece:
                    count += 1
                else:
                    break
            
            if count >= 5:
                return True
        
        return False

    def server_update_ranking(self, winner_id, loser_id):
        """服务器更新排行榜"""
        self.db_manager.update_ranking(winner_id, loser_id)
            
    
    def reset_client_game_state(self, client_id):
        """重置客户端的游戏状态，使其可以参与新的匹配"""
        if client_id in self.clients:
            # 重置游戏ID
            self.clients[client_id]["game_id"] = None
            logging.info(f"客户端 {client_id} ({self.clients[client_id]['username']}) 的游戏状态已重置")

    def get_player_elo(self, username):
        """获取玩家的ELO分数"""
        # 这里应该实现从数据库或文件中获取玩家ELO分数的逻辑
        # 示例实现：如果玩家不存在，返回默认分数1200
        return 1200  # 默认ELO分数
    
    def update_player_elo(self, username, new_elo):
        """更新玩家的ELO分数"""
        # 这里应该实现将玩家的新ELO分数保存到数据库或文件的逻辑
        # 示例：可以使用SQLite数据库或简单的JSON文件存储
        pass
    
    def check_client_heartbeats(self):
        """检查客户端心跳，移除超时客户端"""
        while True:
            current_time = time.time()
            with self.lock:
                clients_to_check = list(self.clients.keys())
            
            for client_id in clients_to_check:
                if client_id in self.client_last_active:
                    last_active = self.client_last_active.get(client_id, 0)
                    # 如果超过30秒没有活动，认为连接已断开
                    if current_time - last_active > 30:
                        logging.info(f"客户端 {client_id} 心跳超时，断开连接")
                        with self.lock:
                            if client_id in self.clients:
                                self.handle_client_disconnect(client_id)
            
            # 每5秒检查一次
            time.sleep(5)

    def on_opponent_info(self, data):
        """处理对手信息的回调 - 已弃用"""
        # 此方法已弃用，排行榜现在由服务器直接更新
        # 保留此方法以兼容旧版本客户端
        print(f"收到对手信息(已弃用): {data}")

    def on_heartbeat_response(self, data):
        # 收到心跳响应，连接正常
        pass

    def disconnect_from_server(self):
        """主动断开与服务器的连接"""
        try:
            # 发送断开连接消息
            self.network.send_message({"type": "client_disconnect"})
            # 关闭连接
            self.network.disconnect()
        except Exception as e:
            print(f"断开连接时出错: {e}")

    def render_game_over_dialog(self):
        """渲染游戏结束对话框"""
        # 创建半透明背景
        overlay = pygame.Surface((self.width, self.height), pygame.SRCALPHA)
        overlay.fill((0, 0, 0, 128))  # 半透明黑色
        self.screen.blit(overlay, (0, 0))
        
        # 对话框尺寸和位置
        dialog_width = 400
        dialog_height = 300
        dialog_x = (self.width - dialog_width) // 2
        dialog_y = (self.height - dialog_height) // 2
        dialog_rect = pygame.Rect(dialog_x, dialog_y, dialog_width, dialog_height)
        
        # 绘制对话框
        pygame.draw.rect(self.screen, self.white, dialog_rect, 0, 12)
        pygame.draw.rect(self.screen, self.apple_blue, dialog_rect, 3, 12)
        
        # 胜利/失败信息
        is_winner = (self.role == "black" and self.winner == "black") or (self.role == "white" and self.winner == "white")
        
        # 绘制标题
        title_text = self.title_font.render("游戏结束", True, self.black)
        title_rect = title_text.get_rect(centerx=dialog_rect.centerx, y=dialog_rect.y + 20)
        self.screen.blit(title_text, title_rect)
        
        # 绘制胜利/失败图片
        img_y = dialog_rect.y + 70
        if is_winner and self.victory_img:
            img_rect = self.victory_img.get_rect(centerx=dialog_rect.centerx, y=img_y)
            self.screen.blit(self.victory_img, img_rect)
        elif not is_winner and self.lose_img:
            img_rect = self.lose_img.get_rect(centerx=dialog_rect.centerx, y=img_y)
            self.screen.blit(self.lose_img, img_rect)
        
        # 绘制提示文本
        tip_text = self.info_font.render("点击此处关闭", True, self.apple_blue)
        tip_rect = tip_text.get_rect(centerx=dialog_rect.centerx, bottom=dialog_rect.bottom - 20)
        self.screen.blit(tip_text, tip_rect)
        
        # 保存关闭按钮区域
        self.close_dialog_rect = tip_rect.inflate(20, 20)

    def render(self):
        # 现有渲染代码...
        
        # 如果游戏结束，显示游戏结束对话框
        if self.game_over and self.show_game_over_dialog:
            self.render_game_over_dialog()

if __name__ == "__main__":
    server = GobangServer()
    server.start()